import numpy as np
from sklearn.datasets import load_digits  # 导入用于加载数据集的函数
from sklearn.model_selection import GridSearchCV, train_test_split  # 导入用于网格搜索和数据集划分的函数
from sklearn.pipeline import Pipeline  # 导入用于创建管道的类
from sklearn.preprocessing import StandardScaler  # 导入用于标准化数据的类
from sklearn.neighbors import KNeighborsClassifier  # 导入KNN分类器
import pickle  # 导入用于保存模型的模块
import matplotlib.pyplot as plt  # 导入用于绘图的模块
from tqdm import tqdm  # 导入用于显示进度条的模块
import matplotlib.font_manager as fm  # 导入字体管理模块

# 使用黑体字体
zh_font = fm.FontProperties(fname='C:/Windows/Fonts/simhei.ttf')

# 加载数字数据集
data = load_digits()
X = data.data
y = data.target

# 将数据集划分为训练集和测试集
X_train, X_test, y_train, y_test = train_test_split(X, y, test_size=0.1, random_state=42)

# 定义参数网格
param_grid = {'knn__n_neighbors': np.arange(1, 41, 2)}

# 创建管道
pipeline = Pipeline([
    ('scaler', StandardScaler()),
    ('knn', KNeighborsClassifier())
])

# 使用网格搜索和交叉验证来选择最佳参数
grid_search = GridSearchCV(pipeline, param_grid, cv=5, scoring='accuracy')
grid_search.fit(X_train, y_train)

# 获取最佳模型和参数
best_model = grid_search.best_estimator_
best_accuracy = grid_search.best_score_
best_k = grid_search.best_params_['knn__n_neighbors']

# 将最佳KNN模型保存到二进制文件
with open('best_knn_model.pkl', 'wb') as file:
    pickle.dump(best_model, file)

# 打印最佳准确率和相应的k值
print(f"最佳准确率: {best_accuracy}, 最佳k值: {best_k}")

# 绘制折线图
plt.figure(figsize=(10, 6))
plt.plot(np.arange(1, 41, 2), grid_search.cv_results_['mean_test_score'])
plt.xlabel('k值')
plt.ylabel('准确率')
plt.title('不同k值的准确率', fontproperties=zh_font)
plt.show()